package com.readaloud.inverted;



import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Random;

import net.sf.ehcache.search.expression.Criteria;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Order;

import com.readaloud.constants.Constants;
import com.readaloud.hibernate.user.Author;
import com.readaloud.hibernate.user.BookClub;
import com.readaloud.hibernate.user.Books;
import com.readaloud.hibernate.user.Comment;
import com.readaloud.indexing.Invertedindex;
import com.readaloud.indexing.KeyWord;
import com.readaloud.indexing.stopwords.StopWords;
import com.readaloud.indexing.stopwords.StopWordsFile;
import com.readaloud.mongo.InvertedIndexMongo;

public class Registry {
	public static final String sStopWords = "stop.words.file";
	public static final String sDataStorage = "data.storage";
	public static final String sIndexStorage = "index.storage";

	
	
	public enum Match {
		Or, And, Proximity
	}

	// TODO abstract/isolate storage. oh yeah and persist it too
	private HashMap<String, ArrayList<Books>> index = new HashMap<String, ArrayList<Books>>();

	private Loader loader;
	private Properties conf;

	public Registry(){
		
	}
	public Registry(Properties conf) {
		this.conf = conf;
		setup();
	}

	/**
	 * find all documents containing these key words - union.
	 * 
	 * TODO allow for union and intersection
	 * 
	 * @param keywords
	 * @return
	 */
	public List<Books> query(List<String> keywords,Session session) {
		if (keywords == null || keywords.size() == 0)
			return null;

		// TODO break down the keywords into separate words for searching (e.g.,
		// 'san jose' => 'san' 'jose')


		ArrayList<Books> r = new ArrayList<Books>();
		for (String keyword : keywords) {
			try {
				// select * from document d,invertedindex_document i where
				// d.docid=i.doc_docid and i.invertedindex_words='lewis';
				// Query query = session
				// .createQuery("select new gash.hibernate.app.Card(p.firstName, p.lastName, c.value) from Person as p join p.contacts as c where p.role = :role and c.type = :type");
				Query findDocuments = session
						.createQuery("from Invertedindex i left join i.doc where i.words='" + keyword + "'");// i left join i.document d");
				org.hibernate.Criteria criteria = session.createCriteria(KeyWord.class);
				criteria.addOrder(Order.desc("standardDeviation"));
				List<Books> books = findDocuments.list();

				Iterator itr = books.iterator();
				while (itr.hasNext()) {
					Object[] pair = (Object[]) itr.next();
					Invertedindex in = (Invertedindex) pair[0];
					Books book = (Books) pair[1];
					Query findComments = session
							.createQuery("from Comment c where c.books = '"
									+ book.getBookId() + "'");
					List<Comment> comment = findComments.list();
					book.setComment(comment);

					System.out.println(book.getComment().size());
					if (!r.contains(book)){
						r.add(book);
					}
				}
				// query.setString("role", role);
				// query.setString("type", "email");

				// the join creates duplicate records - this will remove them

			} catch (RuntimeException e) {
				session.getTransaction().rollback();
				throw e;
			}
		}
		//return r;
	
		
		/*ArrayList<Document> r = new ArrayList<Document>();
		for (String w : keywords) {
			ArrayList<Document> sub = index.get(w);
			if (sub != null) {
				for (Document d : sub) {
					if (!r.contains(d))
						r.addAll(sub);
				}
			}
		}*/

		return r;
	}
	
	public List<Books> searchByGenre(List<String> keywords,Session session, String genre) {
		if (keywords == null || keywords.size() == 0)
			return null;

		// TODO break down the keywords into separate words for searching (e.g.,
		// 'san jose' => 'san' 'jose')


		ArrayList<Books> r = new ArrayList<Books>();
		for (String keyword : keywords) {
			try {
				// select * from books b,invertedindex_books i, bookclub bc
				// where b.bookid=i.doc_bookid and b.bookclub_clubid = bc.clubid
				// and bc.genre = 'Fiction' and i.invertedindex_words='lewis'; //
				// Query query = session
				// .createQuery("select new gash.hibernate.app.Card(p.firstName, p.lastName, c.value) from Person as p join p.contacts as c where p.role = :role and c.type = :type");
				System.out.println("************************************** before query!");
				Query findDocuments = session
						.createQuery("from Books b left join b.bookClub bc, Invertedindex i left join i.doc where bc.genre = '" + genre + "' and i.words='" + keyword + "'");// i left join i.document d");
				List<Books> books = findDocuments.list();
				System.out.println("************************************** after query!");
				Iterator itr = books.iterator();
				while (itr.hasNext()) {
					Object[] pair = (Object[]) itr.next();
					Invertedindex in = (Invertedindex) pair[2];
					Books book = (Books) pair[0];
					Query findComments = session
							.createQuery("from Comment c where c.books = '"
									+ book.getBookId() + "'");
					List<Comment> comment = findComments.list();
					book.setComment(comment);

					System.out.println(book.getComment().size());
					if (!r.contains(book)){
						r.add(book);
					}
				}
				// query.setString("role", role);
				// query.setString("type", "email");

				// the join creates duplicate records - this will remove them

			} catch (RuntimeException e) {
				session.getTransaction().rollback();
				throw e;
			}
		}
		//return r;
	
		
		/*ArrayList<Document> r = new ArrayList<Document>();
		for (String w : keywords) {
			ArrayList<Document> sub = index.get(w);
			if (sub != null) {
				for (Document d : sub) {
					if (!r.contains(d))
						r.addAll(sub);
				}
			}
		}*/

		return r;
	}

	public void register(File f,Session session) {
		if (f == null)
			return;

		// TODO prevent double registration

		List<Books> bookList = loader.load(f);
		//SessionFactory sessionFactory1 = new Configuration().configure().buildSessionFactory();
		//Session session1 = sessionFactory1.openSession();
		//session1.beginTransaction();

		BookParser bookParser = new BookParser();
		for (Books book : bookList) {
			
			System.out.println("size"+ book.getKeywords().size() );
			book = bookParser.parsebook(book);
			//book.parsebook(f);

			Random ran = new Random(System.currentTimeMillis());
			BookClub bookClub = new BookClub();
			bookClub.setGenre(Constants.GENRE[ran.nextInt(Constants.GENRE.length)]); 
			bookClub.setAgeGroup(Constants.AGE_GROUP[ran.nextInt(Constants.AGE_GROUP.length)]);
			book.setBookClub(bookClub);
			
			
			Author author = new Author();
			author.setAuthorName(book.getAuthor());
			author.getBook().add(book);
			author.setUserName("guestName");
			author.setPassword("guestPassword");
			
			book.setAuthorObject(author);
			session.save(bookClub);
			session.persist(book);
			session.persist(author);
			for (KeyWord kw : bookParser.keywords(book)) {
				
				Invertedindex invertedIndex_word = (Invertedindex) session.get(Invertedindex.class, kw.getWord());
				//Invertedindex invertedIndexData = new Invertedindex();
				if(invertedIndex_word == null)
				{	
					invertedIndex_word = new Invertedindex();
					invertedIndex_word.setWords(kw.getWord());
					invertedIndex_word.getDoc().add(book);
					session.save(invertedIndex_word);
					//session1.save(d);
				}
				else {
					invertedIndex_word.getDoc().add(book);
					session.flush();
				}
				
			
				
				/*ArrayList<Document> list = index.get(kw.word);
				if (list == null) {
					list = new ArrayList<Document>();
					index.put(kw.word, list);
				}

				list.add(d);*/
				 				
				
				
			}
		}
		session.getTransaction().commit();
		InvertedIndexMongo invertedIndexMongo = new InvertedIndexMongo();
		invertedIndexMongo.saveKeywordMongo(bookList);
		
		//session1.close();
	}

	private void setup() {
		try {
			//File idir = new File(conf.getProperty(sIndexStorage));

			File swf = new File(conf.getProperty(sStopWords));
			StopWords swords = new StopWordsFile(swf);
			loader = new Loader(swords);
		} catch (Exception e) {
			throw new RuntimeException("Failed to setup registry.", e);
		}
	}
}
